#include "compiler.hpp"
#include "runner.hpp"
#include <jsoncpp/json/json.h>
#include <signal.h>
#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace ns_compile_run
{
    using namespace ns_compiler;
    using namespace ns_runner;
    using namespace ns_util;
    using namespace ns_log;

    class compile_run
    {
    public:
        static void cleartemp_task(const std::string &file_name)
        {
            if (file_util::is_file_exists(path_util::src_cpp(file_name)))
                unlink(path_util::src_cpp(file_name).c_str());
            if (file_util::is_file_exists(path_util::dest_exe(file_name)))
                unlink(path_util::dest_exe(file_name).c_str());
            if (file_util::is_file_exists(path_util::compiler_err(file_name)))
                unlink(path_util::compiler_err(file_name).c_str());
            if (file_util::is_file_exists(path_util::std_err(file_name)))
                unlink(path_util::std_err(file_name).c_str());
            if (file_util::is_file_exists(path_util::std_in(file_name)))
                unlink(path_util::std_in(file_name).c_str());
            if (file_util::is_file_exists(path_util::std_out(file_name)))
                unlink(path_util::std_out(file_name).c_str());
        }

    public:
        static std::string signal_Todesc(int code_status)
        {
            std::string Todesc;
            switch (code_status)
            {
            case SIGABRT:
                Todesc = "内存超过范围";
                break; // 6
            case SIGXCPU:
                Todesc = "时间超过范围";
                break; // 24
            case SIGFPE:
                Todesc = "代码溢出";
                break; // 8
            default:
                Todesc = "debug" + std::to_string(code_status);
                break;
            }
            return Todesc;
        }

    public:
        /*******************************************
         * 输入：
         * 1.code:用户提交的代码
         * 2.input:用户给自己提交的代码对应的输入，不做处理
         * 3.cpu_limit:时间要求
         * 4.mem_limit:空间要求
         * 输出：
         * 1.（必填）status：状态码 reason：请求结果
         * 2.（选填）stdout：程序运行完的结果 stderr：程序运行完的错误结果
         ********************************************/
        /*in_json:{"code":"#include...","input":" ","cpu_limit":1,"mem_limit":10*1024}*/
        /*out_json:{"status":"0","reason":" ","stdout":" ","stderr":" "}*/
        static void start(const std::string &in_json, std::string *out_json)
        {
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);

            std::string code = in_value["code"].asCString();
            std::string input = in_value["input"].asCString();
            int cpu_limit = in_value["cpu_limit"].asInt();
            int mem_limit = in_value["mem_limit"].asInt();

            Json::Value out_value;
            Json::StyledWriter writer;
            if (code.size() == 0)
            {
                /*提交的为空代码*/
                out_value["status"] = -1; // 代码为空
                out_value["reason"] = "用户提交的代码为空";
                *out_json = writer.write(out_value);
                return;
            }
            /*形成的文件名只具有唯一性，没有目录没有后缀*/
            std::string file_name = file_util::unique_file_name();

            if (!file_util::write_file(path_util::src_cpp(file_name), code))
            {
                out_value["status"] = -2; // 未知错误
                out_value["reason"] = "代码发生了未知错误";
                *out_json = writer.write(out_value);
                return;
            }

            std::string _context_compiler_err;
            if (!compiler::compile(file_name))
            {
                out_value["status"] = -3; // 编译错误
                file_util::read_file(path_util::compiler_err(file_name), &_context_compiler_err);
                out_value["reason"] = _context_compiler_err;
                *out_json = writer.write(out_value);
                cleartemp_task(file_name);
                return;
            }

            std::string _context_std_out;
            std::string _context_std_err;
            int code_status = runner::run(file_name, cpu_limit, mem_limit);
            // int code_status = runner::run(file_name);
            file_util::read_file(path_util::std_out(file_name), &_context_std_out);
            file_util::read_file(path_util::std_err(file_name), &_context_std_err);
            if (code_status == 0)
            {
                out_value["status"] = 0; // 程序运行成功
                out_value["reason"] = "代码运行成功";
                out_value["stdout"] = _context_std_out;
                out_value["stderr"] = _context_std_err;
                // Json::FastWriter writer;
                // std::string str=writer.write(out_value);
                // std::cout<<str<<std::endl;
                *out_json = writer.write(out_value);
                cleartemp_task(file_name);
            }
            else if (code_status < 0)
            {
                out_value["status"] = -2; // 程序运行未知错误
                out_value["reason"] = "代码发生了未知错误";
                *out_json = writer.write(out_value);
                cleartemp_task(file_name);
                return;
            }
            else
            {
                out_value["status"] = code_status;                // 程序运行崩溃
                out_value["reason"] = signal_Todesc(code_status); // 信号解析，输出运行奔溃原因
                *out_json = writer.write(out_value);
                cleartemp_task(file_name);
                return;
            }
        }
    };
}
